package Default;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Timer;


import javax.swing.JFrame;

public class Gravilux extends JFrame implements Runnable {

	private ArrayList<Body> bodies = new ArrayList<Body>();
	private PointerInfo pointerInfo;
	private BufferStrategy bufferStrategy;
	private Point cursor;
	private boolean attract = false;
	private double dT = 0.0000002;
	private static double mouseMass = 0;
	private static double activemouseMass = 10000000000000.0;
	private static double Grav_Const = 900000000.0;
	private static double kFriction = 2.0;
	private static int screenHeight = 768;
	private static int screenWidth = 1366;
	private static double rightBound = screenWidth - 20.0;
	private static double leftBound = 20.0;
	private static double lowerBound = screenHeight - 20.0;;
	private static double upperBound = 20.0;
	private static double distanceMinBound = 800000000;
	private static double kColorConstant = 10000.0;
	
	public Gravilux() {
		for(int i = 0; i < screenWidth; i+= 10) {
			for(int ii = 0; ii < screenHeight; ii+=10) {
				bodies.add(new Body(i, ii, 5));
			}
		}
		
		
		//this.createBufferStrategy(2);
		
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent we) {
				System.exit(0);
			}
		});
		this.addMouseListener( new MouseAdapter() {
			//Should turn attracting on
			public void mousePressed(MouseEvent e) {
				mouseMass = activemouseMass;
				//System.out.println("Mouse Pressed");
			}
			
			//Should turn attracting off again
			public void mouseReleased(MouseEvent e) {
				mouseMass = 0;
				//System.out.println("Mouse Released");
			}
		});
		this.setSize(screenWidth, screenHeight);
		
	}
	
	public void start() {
		Thread th = new Thread(this);
		th.start();
		
	}
	
	public static void main(String[] args) {
		Gravilux g = new Gravilux();
		
		g.setVisible(true);
		g.start();
	}

	@Override
	public void run() {
		this.createBufferStrategy(2);
		while(true) {
			BufferStrategy bf = this.getBufferStrategy();
			Graphics g = null;
			try {
				g = bf.getDrawGraphics();
				paint(g);
			} finally {
				g.dispose();
			}
			pointerInfo = MouseInfo.getPointerInfo();
			cursor = pointerInfo.getLocation();
			attractToMouse(bodies);
			
			//repaint();
			bf.show();
			Toolkit.getDefaultToolkit().sync();
			//System.out.println(attract);
			
//			try{
//				Thread.sleep((long) (dT*1000));
//			} catch (InterruptedException exception) {
//				//Do nothing
//			}
		}
	}
	
	
	
	@Override
	public void paint(Graphics g) {
		//super.setBackground(new Color(0, 0, 0));
		super.paint(g);
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, screenWidth, screenHeight);
		for(Body b : bodies) {
			if(b.getVelocity().length() / kColorConstant > 255) {
				g.setColor(new Color(0, 255, 0));
			}
			if(b.getVelocity().length() / kColorConstant < 255 && b.getVelocity().length() > 0) {
				g.setColor(new Color(0, (int)(b.getVelocity().length() / kColorConstant), (int)(255 - (b.getVelocity().length() / kColorConstant))));
			}
			if(b.getVelocity().length() == 0) {
				g.setColor(new Color(0, 0, 255));
			}
			g.fillOval((int)b.getPosition().x, (int)b.getPosition().y, b.getRadius(), b.getRadius());
		}
	}
	
	
	//Should move all bodies closer to the mouse position
	//Calculate using F=ma and working backwards to get position, velocity, etc...
	public void attractToMouse(ArrayList<Body> things) {
		double rDotR;
		for(Body b : things) {
			Vector r = new Vector(cursor.getX(), cursor.getY(), 0).sub(b.getPosition());
			if(r.dot(r) > distanceMinBound) {
				rDotR = r.dot(r);
			} else {
				rDotR = distanceMinBound;
			}
			double fGrav = (b.getMass() * mouseMass * Grav_Const) / rDotR;
			//System.out.println(mouseMass);
			Vector grav = new Vector(cursor.getX(), cursor.getY(), 0.0).sub(b.getPosition());
			grav = grav.norm();
			grav = grav.mult(fGrav);
			//System.out.println(fGrav);
			Vector friction = b.getVelocity().mult(-kFriction);
			Vector totalForce = friction.add(grav);
			Vector acceleration = totalForce.div(b.getMass());
			b.setPosition(b.getPosition().add(b.getVelocity().mult(dT).add(acceleration.mult(Math.pow(dT,2)).mult(0.5))));
			if(b.getPosition().getX() > rightBound) {
				b.setPosition(new Vector(rightBound, b.getPosition().getY(), 0));
				b.setVelocity(new Vector(-b.getVelocity().getX(), b.getVelocity().getY(), 0));
			}
			if(b.getPosition().getX() < leftBound) {
				b.setPosition(new Vector(leftBound, b.getPosition().getY(), 0));
				b.setVelocity(new Vector(-b.getVelocity().getX(), b.getVelocity().getY(), 0));
			}
			if(b.getPosition().getY() > lowerBound) {
				b.setPosition(new Vector(b.getPosition().getX(), lowerBound, 0));
				b.setVelocity(new Vector(b.getVelocity().getX(), -b.getVelocity().getY(), 0));
			}
			if(b.getPosition().getY() < upperBound) {
				b.setPosition(new Vector(b.getPosition().getX(), upperBound, 0));
				b.setVelocity(new Vector(b.getVelocity().getX(), -b.getVelocity().getY(), 0));
			}
			b.setVelocity(b.getVelocity().add(acceleration.mult(dT)));
		}
	}
	

}
